//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using CommunityServer.Components;
using CommunityServer.Controls;
using CA = ComponentArt.Web.UI;
using System.Collections;

namespace CommunityServer.Controls 
{
	// *********************************************************************
	//  SearchView
	//
	/// <summary>
	/// This server control is used to display search options and search results
	/// </summary>
	/// 
	// ********************************************************************/
	public class AdvancedSearch : TemplatedWebControl
	{
		#region Properties

		protected string AjaxQueryStringKey
		{
			get
			{
				return "___" + this.ClientID;
			}
		}

		#endregion

		#region Child Controls

		protected IButton SearchButton;
		protected TextBox Keywords, Users, Tags;
		protected DropDownList SortBy;
		protected DropDownList DateComparer;
		protected CA.Calendar StartDate, EndDate;
		protected CA.TreeView SectionTree;
		protected CustomValidator Validator;

		CSContext csContext = CSContext.Current;

		#endregion

		#region Control Event Handlers

		protected override void OnLoad(EventArgs e) 
		{
			if (this.Page.Request.QueryString[AjaxQueryStringKey] != null)
				HandleXmlRequest(this.Page.Request.QueryString[AjaxQueryStringKey]);
			else if (!Page.IsPostBack)
				DataBind();

			base.OnLoad(e);
		}

		#endregion

		#region DataBind

		protected void HandleXmlRequest(string value)
		{
			EnsureChildControls();

			string[] values = value.Split(':');
			ApplicationType appType = (ApplicationType) int.Parse(values[0]);
			CSApplicationData appData = ApplicationSet.Applications[appType];

			bool check = true;
			if (appData != null)
			{
				CA.TreeView tree = new CA.TreeView();
				CA.TreeViewNode node;

				if (values.Length == 1)
				{
					foreach (Group group in appData.Groups())
					{
						node = new CA.TreeViewNode();
						node.ShowCheckBox = true;
						node.Checked = check;
						node.Text = group.Name;
						node.Value = value + ":" + group.GroupID;
						node.ID = node.Value;
						node.ContentCallbackUrl = CreateCallbackUrl((int) appType, group.GroupID);

						tree.Nodes.Add(node);
					}
				}
				else
				{
					foreach (Section section in appData.SectionsByGroup(int.Parse(values[1])))
					{
						node = new CA.TreeViewNode();
						node.ShowCheckBox = true;
						node.Checked = check;
						node.Text = section.Name;
						node.Value = value + ":" + section.SectionID;
						node.ID = node.Value;

						if (section.Sections != null && section.Sections.Count > 0)
						{
							// Sort subforums by name
							section.Sections.Sort(new SectionSorter(SectionSortBy.Name));

							AddSections(node, section.Sections, value);
						}

						tree.Nodes.Add(node);
					}
				}

				Page.Response.Clear();
				Page.Response.ContentType = "text/xml";
				Page.Response.Write(tree.GetXml());
				Page.Response.End();
			}
		}

		protected void AddSections(CA.TreeViewNode parentNode, ArrayList sections, string baseValue)
		{
			CA.TreeViewNode node;

			foreach (Section section in sections)
			{
				node = new CA.TreeViewNode();
				node.ShowCheckBox = true;
				node.Checked = parentNode.Checked;
				node.Text = section.Name;
				node.Value = baseValue + ":" + section.SectionID;
				node.ID = node.Value;

				if (section.Sections != null && section.Sections.Count > 0)
				{
					// Sort subforums by name
					section.Sections.Sort(new SectionSorter(SectionSortBy.Name));

					AddSections(node, section.Sections, baseValue);
				}

				parentNode.Nodes.Add(node);
			}
		}

		public override void DataBind() 
		{
			base.DataBind();
            
			if (SearchButton != null)
				SearchButton.Text = ResourceManager.GetString("Search");

			if (SortBy != null)
			{
				SortBy.Items.Add(new ListItem(ResourceManager.GetString("SearchAdvanced_SortBy_Relevance"), SearchSort.Relevance.ToString()));
				SortBy.Items.Add(new ListItem(ResourceManager.GetString("SearchAdvanced_SortBy_Date_Ascending"), SearchSort.DateAscending.ToString()));
				SortBy.Items.Add(new ListItem(ResourceManager.GetString("SearchAdvanced_SortBy_Date_Descending"), SearchSort.DateDescending.ToString()));
			}

			if (DateComparer != null)
			{
				DateComparer.Items.Add(new ListItem(ResourceManager.GetString("SearchAdvanced_DateComparer_NotSet"), ""));
				DateComparer.Items.Add(new ListItem(ResourceManager.GetString("SearchAdvanced_DateComparer_On"), "on"));
				DateComparer.Items.Add(new ListItem(ResourceManager.GetString("SearchAdvanced_DateComparer_Between"), "between"));
			}

			if (SectionTree != null)
			{
				SectionTree.ClientSideOnNodeCheckChanged = "new Function('node', 'if (node.Checked) { node.CheckAll(); } else { node.UnCheckAll(); var pNode = node.GetParentNode(); while (pNode) { pNode.SetProperty(\\'Checked\\', false); pNode = pNode.GetParentNode(); } } node.ParentTreeView.Render();')";
				SectionTree.ClientSideOnCallbackComplete = "new Function('node', 'if (!node.Checked) { node.UnCheckAll(); node.ParentTreeView.Render(); }')";
				

                CA.TreeViewNode node = null;

                foreach(CSApplicationData data in ApplicationSet.Applications)
				{
                    if(data.Enabled && data.IsSearchable)
					{
						node = new CA.TreeViewNode();
                        node.Text = data.Name;
						node.Checked = true;
						node.ShowCheckBox = true;
                        node.Value = ((int) data.ApplicationType).ToString();
						node.ID = node.Value;
                        node.ContentCallbackUrl = CreateCallbackUrl((int) data.ApplicationType, -1);

						SectionTree.Nodes.Add(node);
					}
				}
			}
		}
		
		#endregion		
		
		#region Skin
                
		protected override void AttachChildControls()
		{            
			SearchButton = FindButton("SearchButton");
			Users = (TextBox) FindControl("Users");
			Keywords = (TextBox) FindControl("Keywords");
			SortBy = (DropDownList) FindControl("SortBy");
			DateComparer = (DropDownList) FindControl("DateComparer");
			StartDate = (CA.Calendar) FindControl("StartDate");
			EndDate = (CA.Calendar) FindControl("EndDate");
			SectionTree = (CA.TreeView) FindControl("SectionTree");
			Validator = (CustomValidator) FindControl("Validator");
			Tags = (TextBox) FindControl("Tags");
			
			InitializeChildControls();

            UsersOnline.SetLocation("Building an Advanced Search");
		}

		private void InitializeChildControls()
		{
			if (SearchButton != null)
				SearchButton.Click += new EventHandler(SearchButton_Click);
		}
		        
		#endregion

		#region Event Handlers

		protected virtual void SearchButton_Click(Object sender, EventArgs e) 
		{
			try 
			{
				if (!IsValid())
					return;

				SearchQuery query = new SearchQuery();

				query.QueryText = Keywords.Text;

				GetSectionSearchStrings(query);

				query.UserNamesToSearch = GetUserNamesToSearchString();

				query.Tags = GetTagsToSearch();

				// Determine sort
				if (SortBy != null)
					query.SortBy = (SearchSort) Enum.Parse(typeof(SearchSort), SortBy.SelectedValue);

				// Determine date range
				if (DateComparer != null && StartDate != null && EndDate != null)
				{
					if (DateComparer.SelectedValue == "on")
					{
						query.StartDate = StartDate.SelectedDate;
						query.EndDate = StartDate.SelectedDate;//.AddDays(1);
					}
					else if (DateComparer.SelectedValue == "between")
					{
						query.StartDate = StartDate.SelectedDate;
						query.EndDate = EndDate.SelectedDate;
					}
				}

				csContext.Context.Response.Redirect(Globals.GetSiteUrls().SearchForText(SearchProvider.Instance().SearchQueryString(query)));
			}
			catch (Exception ex)
			{
				if (!(ex is System.Threading.ThreadAbortException))
				{
					CSException fex = new CSException(CommunityServer.Components.CSExceptionType.SearchUnknownError, ex.Message, ex);
					fex.Log();
				}
			}
		}

		#endregion

		#region Helpers

		protected virtual string[] GetTagsToSearch()
		{
			if (Tags != null && Tags.Text != string.Empty)
			{
				ArrayList tagsToSearch = new ArrayList();

				foreach (string tag in Tags.Text.Split(new char[] {',', ';'}))
				{
					if (!Globals.IsNullorEmpty(tag.Trim()))
						tagsToSearch.Add(tag.Trim());
				}

				return (string[]) tagsToSearch.ToArray(typeof(string));
			}
			else
				return null;
		}

		protected virtual bool IsValid()
		{
			// Check to make sure the user has submitted something to search on
			// to avoid SQL timeouts.
			//
            if (Users.Text.Length == 0 && Keywords.Text.Length == 0 && Tags.Text.Length == 0 && Validator != null)
			{
				Validator.ErrorMessage = ResourceManager.GetString( "SearchAdvanced_Errors_NoKeywords" );
				Validator.IsValid = false;
				return false;
			}

			return true;
		}

		
        protected virtual void GetSectionSearchStrings(SearchQuery query)
		{
			ArrayList applicationsToSearch = new ArrayList();
			ArrayList groupSearchList = new ArrayList();
			ArrayList sectionSearchList = new ArrayList();

			if (SectionTree != null)
			{
				#region Create section search strings by analyzing tree state

				Hashtable handledNodes = new Hashtable();
				ArrayList applicationNodes = new ArrayList();
				ArrayList groupNodes = new ArrayList();
				ArrayList sectionNodes = new ArrayList();

				// CA has an issue with top-leve checked nodes, so do this explicitly
				foreach (CA.TreeViewNode node in SectionTree.Nodes)
				{
					if (node.Checked)
						applicationNodes.Add(node.Value.Split(':'));
				}

				// categorize the checked node types 
				foreach (CA.TreeViewNode node in SectionTree.CheckedNodes)
				{
					string[] values = node.Value.Split(':');
					switch (values.Length)
					{
						case 2:
							groupNodes.Add(values);
							break;

						case 3:
							sectionNodes.Add(values);
							break;
					}
				}

				// shortcut: If all applications are selected, we don't need to generate a section list :-)
				int applicationCount = 0;
				foreach (CSApplicationData appData in ApplicationSet.Applications)
				{
					if (appData.Enabled && appData.IsSearchable)
						applicationCount++;
				}

				if (applicationNodes.Count == applicationCount)
					return;

				// process the nodes by depth (application > group > section)
				foreach (string[] values in applicationNodes)
				{
					applicationsToSearch.Add((ApplicationType) Enum.Parse(typeof(ApplicationType), values[0]));
					handledNodes[values[0]] = true;
				}

				foreach (string[] values in groupNodes)
				{
					if (!handledNodes.ContainsKey(values[0]))
					{
						groupSearchList.Add(int.Parse(values[1]));
						handledNodes[values[0] + ":" + values[1]] = true;
					}
				}

				foreach (string[] values in sectionNodes)
				{
					if (!handledNodes.ContainsKey(values[0]) && !handledNodes.ContainsKey(values[0] + ":" + values[1]))
					{
						sectionSearchList.Add(int.Parse(values[2]));
					}
				}

				query.ApplicationTypes = (ApplicationType[]) applicationsToSearch.ToArray(typeof(ApplicationType));
				query.GroupsToSearch = (int[]) groupSearchList.ToArray(typeof(int));
				query.SectionsToSearch = (int[]) sectionSearchList.ToArray(typeof(int));

				#endregion
			}
		}

		protected virtual string[] GetUserNamesToSearchString()
		{
			ArrayList usersToSearch = new ArrayList();

			if (Users != null && Users.Text != string.Empty) 
			{
				foreach (string user in Users.Text.Split(','))
				{
					if (!Globals.IsNullorEmpty(user))
						usersToSearch.Add(user);
				}

				return (string[]) usersToSearch.ToArray(typeof(string));
			}

			return null;
		}

		protected virtual string CreateCallbackUrl(int appTypeID, int groupID)
		{
			string value = appTypeID.ToString();
			if (groupID > -1)
				value += ":" + groupID;

			value = Page.Server.UrlEncode(value);

			string url = csContext.CurrentUri.AbsoluteUri;

			if (url.IndexOf("?") == -1)
			{
				url += "?" + AjaxQueryStringKey + "=" + value;
			}
			else
			{
				if (url.IndexOf(AjaxQueryStringKey + "=") == -1)
					url += "&" + AjaxQueryStringKey + "=" + value;
				else
					url = System.Text.RegularExpressions.Regex.Replace(url, AjaxQueryStringKey + "=([^&]+)", AjaxQueryStringKey + "=" + value);
			}

			return url;
		}

		#endregion
	}
}

